#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/capability.h>
#include <stdlib.h>
#define STACK_SIZE (1024 * 1024)

static char child_stack[STACK_SIZE];
char *const child_args[] = {
    "/bin/bash",
    NULL,
};

void set_uid_map(pid_t pid, int inside_id, int outside_id, int length)
{
    char path[256];
    snprintf(path, sizeof(path), "/proc/%d/uid_map", pid);
    printf("path: %s\n", path);
    FILE *uid_map = fopen(path, "w");

    fprintf(uid_map, "%d %d %d", inside_id, outside_id, length);
    fclose(uid_map);
}

void set_gid_map(pid_t pid, int inside_id, int outside_id, int length)
{
    char path[256];
    snprintf(path, sizeof(path), "/proc/%d/gid_map", pid);
    printf("path: %s\n", path);
    FILE *gid_map = fopen(path, "w");

    fprintf(gid_map, "%d %d %d", inside_id, outside_id, length);
    fclose(gid_map);
}

int child_main(void *args)
{
    printf("在子进程中!\n");
    set_gid_map(getpid(), 0, 500, 1);
    set_uid_map(getpid(), 0, 500, 1);

    cap_t caps;
    printf("eUID = %ld; eGID = %ld; ", (long)getuid(), (long)getgid());
    caps = cap_get_proc();
    printf("capabilities: %s\n", cap_to_text(caps, NULL));
    execv(child_args[0], child_args);
    return 1;
}

int main()
{
    printf("程序开始: \n");
    cap_t caps;
    printf("eUID = %ld; eGID = %ld; ", (long)getuid(), (long)getgid());
    caps = cap_get_proc();
    printf("capabilities: %s\n", cap_to_text(caps, NULL));

    int child_pid = clone(child_main,
                          child_stack + STACK_SIZE,
                          CLONE_NEWUSER | CLONE_NEWNS | SIGCHLD,
                          NULL);
    printf("errno: %s", strerror(errno));
    waitpid(child_pid, NULL, 0);
    printf("已退出\n");
    return 0;
}